﻿// <copyright file="RPGRoguelikeEngineTestApp.cs" company="TenneySoftware">
// Copyright (c) 2009 All Right Reserved
// </copyright>
// <author>Robert Tenney</author>
// <email>rob10e@yahoo.com</email>
// <date>April 2009</date>
// <summary>Main application display form.</summary>

// License:

// Product: RPGRoguelikeEngine .Net
// Author: Robert N. Tenney
// Copyright: April 2009

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation version 2
// of the License.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

// This license covers all source code, binaries, and other materials related to this project
// unless specifically stated otherwise.

// #define UPDATECHANGELOG

using System;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using TenneySoftware.Engine;
using TenneySoftware.Engine.Characters;
using TenneySoftware.Engine.GraphicsManager;

namespace TenneySoftware.RPGRoguelikeEngineTestApp {
    /// <summary>
    /// Main application display form.
    /// </summary>
    public partial class MainForm : Form {
        /// <summary>
        /// Flag to indicate if the level has been generated.
        /// </summary>
        private bool generated;
        
        /// <summary>
        /// Flag to indicate if we are in panning mode.
        /// </summary>
        private bool panning;
        
        /// <summary>
        /// Display's offset.
        /// </summary>
        private Point offset;
        
        /// <summary>
        /// Display's origin point from offset.
        /// </summary>
        private Point origin;
        
        /// <summary>
        /// Graphic manager list.
        /// </summary>
        private ToolStripItem[] graphicsManagersList;
        
        /// <summary>
        /// Player's character.
        /// </summary>
        private Player player;
        
        /// <summary>
        /// The game engine.
        /// </summary>
        private RPGEngine engine;

        /// <summary>
        /// Initializes a new instance of the MainForm class.
        /// </summary>
        public MainForm() {
            this.InitializeComponent();
            string version = Assembly.GetAssembly(this.GetType()).GetName().Version.ToString();
            this.Text += " " + version;
            #if UPDATECHANGELOG
            FileStream stream = new FileStream(@"..\..\Engine\Changelog.txt", FileMode.Open);
            StreamWriter write = new StreamWriter(stream);
            StreamReader read = new StreamReader(stream);
            read.BaseStream.Seek(16, SeekOrigin.Begin);
            string log = read.ReadToEnd();
            write.BaseStream.Seek(16, SeekOrigin.Begin);
            write.WriteLine("Version: " + version + " - " + DateTime.Now.ToShortDateString());
            write.Write(log);
            write.Close();
            stream.Close();
            #endif
            this.Icon = new Icon(Assembly.GetExecutingAssembly().GetManifestResourceStream("RPGRoguelikeEngineTestApp.roguelike.ico"));
            this.player = new Player("Robert", CharacterRace.Human, CharacterClass.Fighter);
            this.player.VisionRange = 20;
            this.engine = new RPGEngine();
            this.LoadManagers();
            this.LoadGenerators();
            this.Width = 1024;
            this.Height = 768;
        }

        /// <summary>
        /// The main game loop.
        /// </summary>
        private void MainLoop() {
            while (this.Created) {
                if (Actions.ActionsInQueue){
                    Actions.PerformNextAction();
                }

                this.engine.Update();
                Application.DoEvents();
                this.DungeonDisplay.Focus();
            }
        }

        /// <summary>
        /// Sets up the level generator.
        /// </summary>
        private void GeneratorSetup() {
            this.engine.LevelGenerator.SetSize(new Size(100, 100));
            this.ManagerSetup();
        }

        /// <summary>
        /// Sets up the graphics manager.
        /// </summary>
        private void ManagerSetup() {
            // engine.GraphicsManager.CenterPlayer = false;
            this.ResizeIt();
        }

        /// <summary>
        /// Cause the level generator to generate the level.
        /// </summary>
        private void Generate() {
            this.GeneratorSetup();
            this.generated = this.engine.GenerateLevel();
            if (this.generated) {
                this.engine.PlaceCharacterAtStart(this.player);
            }
        }

        /// <summary>
        /// Process the keyboard's input which are non-ascii characters.
        /// </summary>
        /// <param name="key">Key to process.</param>
        private void ProcessOtherKeys(Keys key) {
            if (this.engine.GraphicsManager.Generated) {
                switch (key) {
                    case Keys.Left:
                        this.player.CharacterActions.Walk(Direction.West);
                        break;
                    case Keys.Right:
                        this.player.CharacterActions.Walk(Direction.East);
                        break;
                    case Keys.Up:
                        this.player.CharacterActions.Walk(Direction.North);
                        break;
                    case Keys.Down:
                        this.player.CharacterActions.Walk(Direction.South);
                        break;
                    case Keys.Escape:
                        Environment.Exit(0);
                        break;
                }
            }
        }

        /// <summary>
        /// Process the keyboard's input which are ascii characters.
        /// </summary>
        /// <param name="key">Key to process.</param>
        private void ProcessRegularKeys(char key) {
            if (this.engine.GraphicsManager.Generated) {
                switch (key) {
                    case 'm':
                    case 'M':
                        this.ToggleView();
                        break;
                    case 'r':
                    case 'R':
                        this.Regenerate();
                        break;
                    case 'q':
                    case 'Q':
                        Environment.Exit(0);
                        break;
                    case 'c':
                    case 'C':
                        this.SetCenteringMode("On Player");
                        break;
                    case 's':
                    case 'S':
                        this.SetCenteringMode("On Screen");
                        break;
                    case 'p':
                    case 'P':
                        this.SetCenteringMode("Panning");
                        break;
                    case '~':
                        this.engine.ConsoleModeActive = true;
                        if (this.engine.Console.OutputBuffer.Count == 0) {
                            this.engine.Console.OutputBuffer.Add("Usage:\n\t'?' for usage help.");
                        }
                        
                        break;
                }
            }
        }

        /// <summary>
        /// Toggle the view from main level view and the map view.
        /// </summary>
        private void ToggleView() {
            this.engine.GraphicsManager.ToggleDisplay();
            if (this.menuViewItemMap.Checked) {
                this.menuViewItemLevel.Checked = true;
                this.menuViewItemMap.Checked = false;
            } else {
                this.menuViewItemMap.Checked = true;
                this.menuViewItemLevel.Checked = false;
            }
        }

        /// <summary>
        /// Causes the level to be regenerated.
        /// </summary>
        private void Regenerate() {
            string name = this.engine.LevelGenerator.ModuleName;
            string predef = this.engine.LevelGenerator.SettingsName;
            this.GeneratorSelect(name, predef);
            this.Generate();
            this.engine.GraphicsManager.Reset();
            this.engine.GraphicsManager.Invalidate();
            this.engine.Update();
        }

        /// <summary>
        /// Updates the display with the resized values.
        /// </summary>
        private void ResizeIt() {
            this.engine.GraphicsManager.SetGraphicsDevice(this.DungeonDisplay);
        }

        /// <summary>
        /// Sets the centering mode.
        /// </summary>
        /// <param name="mode">Centering mode to use.</param>
        private void SetCenteringMode(string mode) {
            switch (mode) {
                case "On Player":
                    this.onPlayerToolStripMenuItem.Checked = true;
                    this.onScreenToolStripMenuItem.Checked = false;
                    this.panningToolStripMenuItem.Checked = false;
                    this.engine.GraphicsManager.CenteringModeUsed = CenteringMode.OnPlayer;
                    break;
                case "On Screen":
                    this.onPlayerToolStripMenuItem.Checked = false;
                    this.onScreenToolStripMenuItem.Checked = true;
                    this.panningToolStripMenuItem.Checked = false;
                    this.engine.GraphicsManager.CenteringModeUsed = CenteringMode.OnScreen;
                    break;
                case "Panning":
                    this.onPlayerToolStripMenuItem.Checked = false;
                    this.onScreenToolStripMenuItem.Checked = false;
                    this.panningToolStripMenuItem.Checked = true;
                    this.engine.GraphicsManager.CenteringModeUsed = CenteringMode.UserDefined;
                    break;
            }
        }
    }
}
